﻿package kr.flas.automaton
{
	import kr.flas.events.HangulAutomatonEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.events.TextEvent;
	import flash.system.IME;
	import flash.system.IMEConversionMode;
	import flash.text.TextField;
	import flash.ui.Keyboard;
	
	/**
	 * 한글조합기 Hangul Automaton
	 */
	public class HangulAutomaton extends EventDispatcher
	{
		/**
		 * 비어있는 상태를 나타내는 코드
		 */
		public static const CODE_BLANK:int = -1;
		
		private static const CONSONANT:String = "consonant";
		private static const VOWEL:String = "vowel";
		private static const UNDEFINED:String = "undefined";
		
		public static const A_ㄱ:int = 0x72;
		public static const A_ㄲ:int = 0x52;
		public static const A_ㄴ:int = 0x73;
		public static const A_ㄷ:int = 0x65;
		public static const A_ㄸ:int = 0x45;
		public static const A_ㄹ:int = 0x66;
		public static const A_ㅁ:int = 0x61;
		public static const A_ㅂ:int = 0x71;
		public static const A_ㅃ:int = 0x51;
		public static const A_ㅅ:int = 0x74;
		public static const A_ㅆ:int = 0x54;
		public static const A_ㅇ:int = 0x64;
		public static const A_ㅈ:int = 0x77;
		public static const A_ㅉ:int = 0x57;
		public static const A_ㅊ:int = 0x63;
		public static const A_ㅋ:int = 0x7A;
		public static const A_ㅌ:int = 0x78;
		public static const A_ㅍ:int = 0x76;
		public static const A_ㅎ:int = 0x67;
		
		public static const A_ㅏ:int = 0x6B;
		public static const A_ㅐ:int = 0x6F;
		public static const A_ㅑ:int = 0x69;
		public static const A_ㅒ:int = 0x4F;
		public static const A_ㅓ:int = 0x6A;
		public static const A_ㅔ:int = 0x70;
		public static const A_ㅕ:int = 0x75;
		public static const A_ㅖ:int = 0x50;
		public static const A_ㅗ:int = 0x68;
		public static const A_ㅛ:int = 0x79;
		public static const A_ㅜ:int = 0x6E;
		public static const A_ㅠ:int = 0x62;
		public static const A_ㅡ:int = 0x6D;
		public static const A_ㅣ:int = 0x6C;
		
		public static const C_ㄱ:int = 0;
		public static const C_ㄲ:int = 1;
		public static const C_ㄳ:int = 2;
		public static const C_ㄴ:int = 3;
		public static const C_ㄵ:int = 4;
		public static const C_ㄶ:int = 5;
		public static const C_ㄷ:int = 6;
		public static const C_ㄸ:int = 7;
		public static const C_ㄹ:int = 8;
		public static const C_ㄺ:int = 9;
		public static const C_ㄻ:int = 10;
		public static const C_ㄼ:int = 11;
		public static const C_ㄽ:int = 12;
		public static const C_ㄾ:int = 13;
		public static const C_ㄿ:int = 14;
		public static const C_ㅀ:int = 15;
		public static const C_ㅁ:int = 16;
		public static const C_ㅂ:int = 17;
		public static const C_ㅃ:int = 18;
		public static const C_ㅄ:int = 19;
		public static const C_ㅅ:int = 20;
		public static const C_ㅆ:int = 21;
		public static const C_ㅇ:int = 22;
		public static const C_ㅈ:int = 23;
		public static const C_ㅉ:int = 24;
		public static const C_ㅊ:int = 25;
		public static const C_ㅋ:int = 26;
		public static const C_ㅌ:int = 27;
		public static const C_ㅍ:int = 28;
		public static const C_ㅎ:int = 29;
		
		public static const V_ㅏ:int = 0;
		public static const V_ㅐ:int = 1;
		public static const V_ㅑ:int = 2;
		public static const V_ㅒ:int = 3;
		public static const V_ㅓ:int = 4;
		public static const V_ㅔ:int = 5;
		public static const V_ㅕ:int = 6;
		public static const V_ㅖ:int = 7;
		public static const V_ㅗ:int = 8;
		public static const V_ㅘ:int = 9;
		public static const V_ㅙ:int = 10;
		public static const V_ㅚ:int = 11;
		public static const V_ㅛ:int = 12;
		public static const V_ㅜ:int = 13;
		public static const V_ㅝ:int = 14;
		public static const V_ㅞ:int = 15;
		public static const V_ㅟ:int = 16;
		public static const V_ㅠ:int = 17;
		public static const V_ㅡ:int = 18;
		public static const V_ㅢ:int = 19;
		public static const V_ㅣ:int = 20;
		
		public static const I_ㄱ:int = 0;
		public static const I_ㄲ:int = 1;
		public static const I_ㄴ:int = 2;
		public static const I_ㄷ:int = 3;
		public static const I_ㄸ:int = 4;
		public static const I_ㄹ:int = 5;
		public static const I_ㅁ:int = 6;
		public static const I_ㅂ:int = 7;
		public static const I_ㅃ:int = 8;
		public static const I_ㅅ:int = 9;
		public static const I_ㅆ:int = 10;
		public static const I_ㅇ:int = 11;
		public static const I_ㅈ:int = 12;
		public static const I_ㅉ:int = 13;
		public static const I_ㅊ:int = 14;
		public static const I_ㅋ:int = 15;
		public static const I_ㅌ:int = 16;
		public static const I_ㅍ:int = 17;
		public static const I_ㅎ:int = 18;
		
		public static const F_ㄱ:int = 1;
		public static const F_ㄲ:int = 2;
		public static const F_ㄳ:int = 3;
		public static const F_ㄴ:int = 4;
		public static const F_ㄵ:int = 5;
		public static const F_ㄶ:int = 6;
		public static const F_ㄷ:int = 7;
		public static const F_ㄹ:int = 8;
		public static const F_ㄺ:int = 9;
		public static const F_ㄻ:int = 10;
		public static const F_ㄼ:int = 11;
		public static const F_ㄽ:int = 12;
		public static const F_ㄾ:int = 13;
		public static const F_ㄿ:int = 14;
		public static const F_ㅀ:int = 15;
		public static const F_ㅁ:int = 16;
		public static const F_ㅂ:int = 17;
		public static const F_ㅄ:int = 18;
		public static const F_ㅅ:int = 19;
		public static const F_ㅆ:int = 20;
		public static const F_ㅇ:int = 21;
		public static const F_ㅈ:int = 22;
		public static const F_ㅊ:int = 23;
		public static const F_ㅋ:int = 24;
		public static const F_ㅌ:int = 25;
		public static const F_ㅍ:int = 26;
		public static const F_ㅎ:int = 27;
		
		/**
		 * 입력된 음소의 배열
		 */
		protected var _array_code:Array;
		/**
		 * 초성 코드
		 */
		protected var _init_code:int;
		/**
		 * 중성 코드
		 */
		protected var _middle_code:int;
		/**
		 * 종성 코드
		 */
		protected var _final_code:int;
		
		protected var _init_num:int;
		protected var _middle_num:int;
		protected var _final_num:int;
		
		/**
		 * 입력 상태 true:한/false:영
		 */
		private var hmode:Boolean;
		/**
		 * 콘트롤 키 누름 상태
		 */
		private var _is_ctrl:Boolean;
		/**
		 * 알트 키 누름 상태
		 */
		private var _is_alt:Boolean;
		
		private var _is_backspace:Boolean;
		private var _is_movekey_down:Boolean;
		
		private var targetTextField:TextField;
		private var sbi:int;
		private var sei:int;
		
		/**
		 * 생성자
		 */
		public function HangulAutomaton() 
		{
			initializeAutomaton();
		}
		
		/**
		 * 한글조합기 초기화
		 */
		protected function initializeAutomaton():void
		{
			hmode = false;
			_is_ctrl = false;
			_is_alt = false;
			_is_backspace = false;
			_is_movekey_down = false;
			
			initializeCode();
			addEventListener(HangulAutomatonEvent.SYLLABIC_COMPOSED, onSyllabicComposed);
		}
		
		/**
		 * 저장된 코드 초기화
		 */
		protected function initializeCode():void
		{
			_array_code = new Array();
			_init_code = CODE_BLANK;
			_middle_code = CODE_BLANK;
			_final_code = CODE_BLANK;
			_init_num = 0;
			_middle_num = 0;
			_final_num = 0;
		}
		
		public function backspace():String
		{
			var _result:String;
			var _tmp_array_code:Array = _array_code;
			var _tmp_init_num:int = _init_num;
			var _tmp_middle_num:int = _middle_num;
			var _tmp_final_num:int = _final_num;
			var i:int;
			
			initializeCode();
			_tmp_array_code.pop();
			
			if (_tmp_final_num > 0) { _tmp_final_num--; }
			else if (_tmp_middle_num > 0) { _tmp_middle_num--; }
			else if (_tmp_init_num > 0) { _tmp_init_num--; }
			
			for (i = 0; i < _tmp_init_num; i++)
			{addConsonantCode(_tmp_array_code[i], false); }
			
			for ( ; i < _tmp_init_num + _tmp_middle_num ; i++)
			{addVowelCode(_tmp_array_code[i], false); }
			
			for ( ; i < _tmp_init_num + _tmp_middle_num + _tmp_final_num ; i++)
			{addConsonantCode(_tmp_array_code[i], false);}
			
			_result = composeAlphabets(_init_code, _middle_code, _final_code);
			
			return _result;
		}
		
		/**
		 * 자모 추가
		 */
		public function addAlphabet(letter:String):String
		{
			//자모인지 검사
			switch(getTypeFromAlphabet(letter))
			{
			//자모면 추가처리
			case CONSONANT:
				return addConsonantCode(getCodeFromAlphabet(letter));
			break;
			case VOWEL:
				return addVowelCode(getCodeFromAlphabet(letter));
			break;
			
			//아니면 기존에 구성되어있는 코드 배출. 초기화
			case UNDEFINED:
			default:
				releaseSyllabic();
				dispatchEvent(new HangulAutomatonEvent(HangulAutomatonEvent.NO_ALPHABET_ADDED,false,false,letter));
				return letter;
			break;
			}
		}
		
		/**
		 * 자음 코드 추가
		 */
		public function addConsonantCode(code:int, notification:Boolean=true):String
		{
			var _result:String;
			var _tmp_init_code:int;
			var _tmp_final_code:int;
			var _tmp_compose_c:int;
			var _tmp_compose_v:int;
			
			_array_code.push(code);
			
				switch(_init_code)
				{
				//초성 없음
				case CODE_BLANK:
					switch(_middle_code)
					{
					//초성 없음, 중성 없음, 입력 자음
					case CODE_BLANK:
						_init_code = code;
						_init_num = 1;
					break;
					
					//초성 없음, 중성 있음, 입력 자음
					default:
						releaseSyllabic();
						addConsonantCode(code, false);
					break;
					}
				break;
				
				//초성 있음
				default:
					switch(_middle_code)
					{
					//초성 있음, 중성 없음, 입력 자음
					case CODE_BLANK:
						//자음 합성
						_tmp_compose_c = composeConsonants(_init_code, code);
						
						switch(_tmp_compose_c)
						{
						//자음 합성 실패
						case CODE_BLANK:
							releaseSyllabic();
							addConsonantCode(code, false);
						break;
						
						//합성되었다면
						default:
							_init_code = _tmp_compose_c;
							_init_num++;
						break;
						}
					break;
					
					//초성 있음, 중성 있음
					default:
						switch(_final_code)
						{
						//초성 있음, 중성 있음, 종성 없음, 입력 자음
						case CODE_BLANK:
							switch(getEnableFinalCode(code))
							{
							//종성 가능한 자음
							case true:
								_final_code = code;
								_final_num = 1;
							break;
							
							//종성 불가능한 자음
							case false:
							default:
								releaseSyllabic();
								addConsonantCode(code, false);
							break;
							}
						break;
						
						//초성 있음, 중성 있음, 종성 있음, 입력 자음
						default:
							//자음 합성
							_tmp_compose_c = composeConsonants(_final_code, code);
							
							switch(_tmp_compose_c)
							{
							//자음 합성 실패
							case CODE_BLANK:
								releaseSyllabic();
								addConsonantCode(code, false);
							break;
							
							//합성되었다면
							default:
								switch(getEnableFinalCode(_tmp_compose_c))
								{
								//종성 가능한 자음
								case true:
									_final_code = _tmp_compose_c;
									_final_num++;
								break;
								
								//종성 불가능한 자음
								case false:
								default:
									releaseSyllabic();
									addConsonantCode(code, false);
								break;
								}
							break;
							}
						break;
						}
					break;
					}
				break;
				}
				
				_result = composeAlphabets(_init_code, _middle_code, _final_code);
				if (notification)
				{dispatchEvent(new HangulAutomatonEvent(HangulAutomatonEvent.ALPHABET_ADDED, false, false, _result));}
				return _result;
		}
		
		/**
		 * 모음 코드 추가
		 */
		private function addVowelCode(code:int, notification:Boolean=true):String
		{
			var _result:String;
			var _tmp_init_code:int;
			var _tmp_final_code:int;
			var _tmp_compose_c:int;
			var _tmp_compose_v:int;
			
			_array_code.push(code);
			
			
				switch(_init_code)
				{
				//초성 없음
				case CODE_BLANK:
					switch(_middle_code)
					{
					//초성 없음, 중성 없음, 입력 모음
					case CODE_BLANK:
						_middle_code = code;
						_middle_num = 1;
					break;
					
					//초성 없음, 중성 있음, 입력 모음
					default:
						//모음 합성
						_tmp_compose_v = composeVowels(_middle_code, code);
						
						switch(_tmp_compose_v)
						{
						//모음 합성 실패
						case CODE_BLANK:
							releaseSyllabic();
							addVowelCode(code, false);
						break;
						
						//합성되었다면
						default:
							_middle_code = _tmp_compose_v;
							_middle_num++;
						break;
						}
					break;
					}
				break;
				
				//초성 있음
				default:
					switch(_middle_code)
					{
					//초성 있음, 중성 없음, 입력 모음
					case CODE_BLANK:
						switch(_init_num)
						{
						//단자음
						case 1:
							_middle_code = code;
							_middle_num = 1;
						break;
						
						//이중자음
						case 2:
							_tmp_init_code = _array_code[1];
							_init_code = _array_code[0];
							releaseSyllabic();
							addConsonantCode(_tmp_init_code, false);
							addVowelCode(code, false);
						break;
						
						default:
							
						break;
						}
					break;
					
					//초성 있음, 중성 있음
					default:
						switch(_final_code)
						{
						//초성 있음, 중성 있음, 종성 없음, 입력 모음
						case CODE_BLANK:
							//모음 합성
							_tmp_compose_v = composeVowels(_middle_code, code);
							
							switch(_tmp_compose_v)
							{
							//모음 합성 실패
							case CODE_BLANK:
								releaseSyllabic();
								addVowelCode(code, false);
							break;
							
							//합성되었다면
							default:
								_middle_code = _tmp_compose_v;
								_middle_num++;
							break;
							}
						break;
						
						//초성 있음, 중성 있음, 종성 있음, 입력 모음
						default:
							switch(_final_num)
							{
							case 1:
								_tmp_final_code = _final_code;
								_final_code = CODE_BLANK;
								_final_num = 0;
								releaseSyllabic();
								addConsonantCode(_tmp_final_code, false);
								addVowelCode(code, false);
							break;
							
							case 2:
								_tmp_final_code = _array_code[_init_num + _middle_num + 1];
								_final_code = _array_code[_init_num + _middle_num];
								_final_num = 1;
								releaseSyllabic();
								addConsonantCode(_tmp_final_code, false);
								addVowelCode(code, false);
							break;
							
							default:
							
							break;
							}
						break;
						}
					break;
					}
				break;
				}
				_result = composeAlphabets(_init_code, _middle_code, _final_code);
				if (notification)
				{dispatchEvent(new HangulAutomatonEvent(HangulAutomatonEvent.ALPHABET_ADDED,false,false,_result)); }
				return _result;
		}
		
		/**
		 * 조합되어있는 음절 배출
		 * 신규 음절 준비
		 */
		public function releaseSyllabic():void
		{
			var _result:String = composeAlphabets(_init_code, _middle_code, _final_code);
			initializeCode();
			if(_result!="")
			{dispatchEvent(new HangulAutomatonEvent(HangulAutomatonEvent.SYLLABIC_COMPOSED,false,false,_result));}
		}
		
		/**
		 * 자모 합성
		 * @param	_init_code:초성
		 * @param	_middle_code:중성
		 * @param	_final_code:종성
		 * @return	String:합성된 한글 문자
		 */
		protected function composeAlphabets(_init_code:int=CODE_BLANK, _middle_code:int=CODE_BLANK, _final_code:int=CODE_BLANK):String
		{
			//모두 없음
			if (_init_code == CODE_BLANK && _middle_code == CODE_BLANK && _final_code == CODE_BLANK)
			{return ""; }
			//초성 X, 중성 O, 종성 X
			else if (_init_code == CODE_BLANK && _final_code == CODE_BLANK)
			{return String.fromCharCode( 12623 + _middle_code); }
			//초성 O, 중성 X, 종성 X
			else if (_middle_code == CODE_BLANK && _final_code == CODE_BLANK)
			{return String.fromCharCode( 12593 + _init_code); }
			//초성 X, 중성 O, 종성 O
			else if (_init_code == CODE_BLANK)
			{return String.fromCharCode( 44032 + (_middle_code * 28) + getFinalCodeFromConsonantCode(_final_code)); }
			//초성 O, 중성 X, 종성 O
			else if (_middle_code == CODE_BLANK)
			{return String.fromCharCode( 44032 + (getInitCodeFromConsonantCode(_init_code) * 588) + getFinalCodeFromConsonantCode(_final_code)); }
			//초성 O, 중성 O, 종성 X
			else if (_final_code == CODE_BLANK)
			{return String.fromCharCode( 44032 + (getInitCodeFromConsonantCode(_init_code) * 588) + (_middle_code * 28)); }
			//초성 O, 중성 O, 종성 O
			else
			{return String.fromCharCode( 44032 + (getInitCodeFromConsonantCode(_init_code) * 588) + (_middle_code * 28) + getFinalCodeFromConsonantCode(_final_code)); }
		}
		
		/**
		 * 자음 합성
		 * @param	former:선코드
		 * @param	latter:후코드
		 * @return	int:합성된 값, 합성실패시 CODE_BLANK 반환, 자음코드
		 */
		protected function composeConsonants(former:int=CODE_BLANK, latter:int=CODE_BLANK):int
		{
			switch(former)
			{
			case C_ㄱ:
				switch(latter)
				{
				case C_ㅅ:
					return C_ㄳ;
				break;
				
				default:
					return CODE_BLANK;
				break;
				}
			break;
			
			case C_ㄴ:
				switch(latter)
				{
				case C_ㅈ:
					return C_ㄵ;
				break;
				
				case C_ㅎ:
					return C_ㄶ;
				break;
				
				default:
					return CODE_BLANK;
				break;
				}
			break;
			
			case C_ㄹ:
				switch(latter)
				{
				case C_ㄱ:
					return C_ㄺ;
				break;
				
				case C_ㅁ:
					return C_ㄻ;
				break;
				
				case C_ㅂ:
					return C_ㄼ;
				break;
				
				case C_ㅅ:
					return C_ㄽ;
				break;
				
				case C_ㅌ:
					return C_ㄾ;
				break;
				
				case C_ㅍ:
					return C_ㄿ;
				break;
				
				case C_ㅎ:
					return C_ㅀ;
				break;
				
				default:
					return CODE_BLANK;
				break;
				}
			break;
			
			case C_ㅂ:
				switch(latter)
				{
				case C_ㅅ:
					return C_ㅄ;
				break;
				
				default:
					return CODE_BLANK;
				break;
				}
			break;
			
			default:
				return CODE_BLANK;
			break;
			}
		}
		
		/**
		 * 모음 합성
		 * @param	former:선코드
		 * @param	latter:후코드
		 * @return	int:합성된 값, 합성실패시 CODE_BLANK 반환, 모음코드
		 */
		protected function composeVowels(former:int=CODE_BLANK, latter:int=CODE_BLANK):int
		{
			switch(former)
			{
			case V_ㅗ:
				switch(latter)
				{
				case V_ㅏ:
					return V_ㅘ;
				break;
				
				case V_ㅐ:
					return V_ㅙ;
				break;
				
				case V_ㅣ:
					return V_ㅚ;
				break;
				
				default:
					return CODE_BLANK;
				break;
				}
			break;
			
			case V_ㅜ:
				switch(latter)
				{
				case V_ㅓ:
					return V_ㅝ;
				break;
				
				case V_ㅔ:
					return V_ㅞ;
				break;
				
				case V_ㅣ:
					return V_ㅟ;
				break;
				
				default:
					return CODE_BLANK;
				break;
				}
			break;
			
			case V_ㅡ:
				switch(latter)
				{
				case V_ㅣ:
					return V_ㅢ;
				break;
				
				default:
					return CODE_BLANK;
				break;
				}
			break;
			
			default:
				return CODE_BLANK;
			break;
			}
		}
		
		/**
		 * 영어 문자에서 코드값 얻기
		 * @param	letter:코드값을 추출할 영문자
		 * @return	int:추출한 코드값
		 */
		protected function getCodeFromAlphabet(letter:String):int
		{
			switch(letter.charCodeAt(0))
			{
			case A_ㄱ:
				return C_ㄱ;
			break;
			
			case A_ㄲ:
				return C_ㄲ;
			break;
			
			case A_ㄴ:
				return C_ㄴ;
			break;
			
			case A_ㄷ:
				return C_ㄷ;
			break;
			
			case A_ㄸ:
				return C_ㄸ;
			break;
			
			case A_ㄹ:
				return C_ㄹ;
			break;
			
			case A_ㅁ:
				return C_ㅁ;
			break;
			
			case A_ㅂ:
				return C_ㅂ;
			break;
			
			case A_ㅃ:
				return C_ㅃ;
			break;
			
			case A_ㅅ:
				return C_ㅅ;
			break;
			
			case A_ㅆ:
				return C_ㅆ;
			break;
			
			case A_ㅇ:
				return C_ㅇ;
			break;
			
			case A_ㅈ:
				return C_ㅈ;
			break;
			
			case A_ㅉ:
				return C_ㅉ;
			break;
			
			case A_ㅊ:
				return C_ㅊ;
			break;
			
			case A_ㅋ:
				return C_ㅋ;
			break;
			
			case A_ㅌ:
				return C_ㅌ;
			break;
			
			case A_ㅍ:
				return C_ㅍ;
			break;
			
			case A_ㅎ:
				return C_ㅎ;
			break;
			
			case A_ㅏ:
				return V_ㅏ;
			break;
			
			case A_ㅐ:
				return V_ㅐ;
			break;
			
			case A_ㅑ:
				return V_ㅑ;
			break;
			
			case A_ㅒ:
				return V_ㅒ;
			break;
			
			case A_ㅓ:
				return V_ㅓ;
			break;
			
			case A_ㅔ:
				return V_ㅔ;
			break;
			
			case A_ㅕ:
				return V_ㅕ;
			break;
			
			case A_ㅖ:
				return V_ㅖ;
			break;
			
			case A_ㅗ:
				return V_ㅗ;
			break;
			
			case A_ㅛ:
				return V_ㅛ;
			break;
			
			case A_ㅜ:
				return V_ㅜ;
			break;
			
			case A_ㅠ:
				return V_ㅠ;
			break;
			
			case A_ㅡ:
				return V_ㅡ;
			break;
			
			case A_ㅣ:
				return V_ㅣ;
			break;
			
			default:
				return CODE_BLANK;
			break;
			}
		}
		
		/**
		 * 영어문자로 한글의 자음인지 모음인지 검사
		 * @param	letter: 검사할 영어문자
		 * @return	String:	CONSONANT	자음
		 * 					VOWEL		모음
		 * 					UNDEFINED	기타
		 */
		protected function getTypeFromAlphabet(letter:String):String
		{
			switch(letter.charCodeAt(0))
			{
			case A_ㄱ:
			case A_ㄲ:
			case A_ㄴ:
			case A_ㄷ:
			case A_ㄸ:
			case A_ㄹ:
			case A_ㅁ:
			case A_ㅂ:
			case A_ㅃ:
			case A_ㅅ:
			case A_ㅆ:
			case A_ㅇ:
			case A_ㅈ:
			case A_ㅉ:
			case A_ㅊ:
			case A_ㅋ:
			case A_ㅌ:
			case A_ㅍ:
			case A_ㅎ:
				return CONSONANT;
			break;
			
			case A_ㅏ:
			case A_ㅐ:
			case A_ㅑ:
			case A_ㅒ:
			case A_ㅓ:
			case A_ㅔ:
			case A_ㅕ:
			case A_ㅖ:
			case A_ㅗ:
			case A_ㅛ:
			case A_ㅜ:
			case A_ㅠ:
			case A_ㅡ:
			case A_ㅣ:
				return VOWEL;
			break;
			
			default:
				return UNDEFINED;
			break;
			}
		}
		
		/**
		 * 초성이 되는 자모인지 여부
		 * @param	code:자모코드
		 * @return	Boolean:	true	초성
		 * 						false	기타
		 */
		protected function getEnableInitCode(code:int):Boolean
		{
			switch(code)
			{
			case C_ㄱ:
			case C_ㄲ:
			case C_ㄴ:
			case C_ㄷ:
			case C_ㄸ:
			case C_ㄹ:
			case C_ㅁ:
			case C_ㅂ:
			case C_ㅃ:
			case C_ㅅ:
			case C_ㅆ:
			case C_ㅇ:
			case C_ㅈ:
			case C_ㅉ:
			case C_ㅊ:
			case C_ㅋ:
			case C_ㅌ:
			case C_ㅍ:
			case C_ㅎ:
				return true;
			break;
			
			default:
				return false;
			break;
			}
		}
		
		/**
		 * 중성이 되는 자모인지 여부
		 * @param	code:자모코드
		 * @return	Boolean:	true	중성
		 * 						false	기타
		 */
		protected function getEnableMiddleCode(code:int):Boolean
		{
			switch(code)
			{
			case V_ㅏ:
			case V_ㅐ:
			case V_ㅑ:
			case V_ㅒ:
			case V_ㅓ:
			case V_ㅔ:
			case V_ㅕ:
			case V_ㅖ:
			case V_ㅗ:
			case V_ㅘ:
			case V_ㅙ:
			case V_ㅚ:
			case V_ㅛ:
			case V_ㅜ:
			case V_ㅝ:
			case V_ㅞ:
			case V_ㅟ:
			case V_ㅠ:
			case V_ㅡ:
			case V_ㅢ:
			case V_ㅣ:
				return true;
			break;
			
			default:
				return false;
			break;
			}
		}
		
		/**
		 * 종성이 되는 자모인지 여부
		 * @param	code:자모코드
		 * @return	Boolean:	true	종성
		 * 						false	기타
		 */
		protected function getEnableFinalCode(code:int):Boolean
		{
			switch(code)
			{
			case C_ㄱ:
			case C_ㄲ:
			case C_ㄳ:
			case C_ㄴ:
			case C_ㄵ:
			case C_ㄶ:
			case C_ㄷ:
			case C_ㄹ:
			case C_ㄺ:
			case C_ㄻ:
			case C_ㄼ:
			case C_ㄽ:
			case C_ㄾ:
			case C_ㄿ:
			case C_ㅀ:
			case C_ㅁ:
			case C_ㅂ:
			case C_ㅄ:
			case C_ㅅ:
			case C_ㅆ:
			case C_ㅇ:
			case C_ㅈ:
			case C_ㅊ:
			case C_ㅋ:
			case C_ㅌ:
			case C_ㅍ:
			case C_ㅎ:
				return true;
			break;
			
			default:
				return false;
			break;
			}
		}
		
		/**
		 * 자음코드를 초성코드로 변환
		 * @param	code:자음코드
		 * @return	int:초성코드
		 */
		protected function getInitCodeFromConsonantCode(code:int):int
		{
			switch(code)
			{
			case C_ㄱ:
				return I_ㄱ;
			break;
			
			case C_ㄲ:
				return I_ㄲ;
			break;
			
			case C_ㄴ:
				return I_ㄴ;
			break;
			
			case C_ㄷ:
				return I_ㄷ;
			break;
			
			case C_ㄸ:
				return I_ㄸ;
			break;
			
			case C_ㄹ:
				return I_ㄹ;
			break;
			
			case C_ㅁ:
				return I_ㅁ;
			break;
			
			case C_ㅂ:
				return I_ㅂ;
			break;
			
			case C_ㅃ:
				return I_ㅃ;
			break;
			
			case C_ㅅ:
				return I_ㅅ;
			break;
			
			case C_ㅆ:
				return I_ㅆ;
			break;
			
			case C_ㅇ:
				return I_ㅇ;
			break;
			
			case C_ㅈ:
				return I_ㅈ;
			break;
			
			case C_ㅉ:
				return I_ㅉ;
			break;
			
			case C_ㅊ:
				return I_ㅊ;
			break;
			
			case C_ㅋ:
				return I_ㅋ;
			break;
			
			case C_ㅌ:
				return I_ㅌ;
			break;
			
			case C_ㅍ:
				return I_ㅍ;
			break;
			
			case C_ㅎ:
				return I_ㅎ;
			break;
			
			default:
				return CODE_BLANK;
			break;
			}
		}
		
		/**
		 * 자음코드를 종성코드로 변환
		 * @param	code:자음코드
		 * @return	int:종성코드
		 */
		protected function getFinalCodeFromConsonantCode(code:int):int
		{
			switch(code)
			{
			case C_ㄱ:
				return F_ㄱ;
			break;
			
			case C_ㄲ:
				return F_ㄲ;
			break;
			
			case C_ㄳ:
				return F_ㄳ;
			break;
			
			case C_ㄴ:
				return F_ㄴ;
			break;
			
			case C_ㄵ:
				return F_ㄵ;
			break;
			
			case C_ㄶ:
				return F_ㄶ;
			break;
			
			case C_ㄷ:
				return F_ㄷ;
			break;
			
			case C_ㄹ:
				return F_ㄹ;
			break;
			
			case C_ㄺ:
				return F_ㄺ;
			break;
			
			case C_ㄻ:
				return F_ㄻ;
			break;
			
			case C_ㄼ:
				return F_ㄼ;
			break;
			
			case C_ㄽ:
				return F_ㄽ;
			break;
			
			case C_ㄾ:
				return F_ㄾ;
			break;
			
			case C_ㄿ:
				return F_ㄿ;
			break;
			
			case C_ㅀ:
				return F_ㅀ;
			break;
			
			case C_ㅁ:
				return F_ㅁ;
			break;
			
			case C_ㅂ:
				return F_ㅂ;
			break;
			
			case C_ㅄ:
				return F_ㅄ;
			break;
			
			case C_ㅅ:
				return F_ㅅ;
			break;
			
			case C_ㅆ:
				return F_ㅆ;
			break;
			
			case C_ㅇ:
				return F_ㅇ;
			break;
			
			case C_ㅈ:
				return F_ㅈ;
			break;
			
			case C_ㅊ:
				return F_ㅊ;
			break;
			
			case C_ㅋ:
				return F_ㅋ;
			break;
			
			case C_ㅌ:
				return F_ㅌ;
			break;
			
			case C_ㅍ:
				return F_ㅍ;
			break;
			
			case C_ㅎ:
				return F_ㅎ;
			break;
			
			default:
				return CODE_BLANK;
			break;
			}
		}
		
		/**
		 * 이벤트 핸들러, 한 문자 조합되서 나올 때.
		 * @param	event
		 */
		protected function onSyllabicComposed(event:HangulAutomatonEvent):void
		{
			if (targetTextField)
			{
				//sbi = targetTextField.selectionBeginIndex;
				sei = sbi + event.syllabic.length;
				
				targetTextField.replaceText(sbi, sei, event.syllabic);
				targetTextField.setSelection(sei, sbi);
				sbi++;
				sei = sbi;
				targetTextField.dispatchEvent(new Event(Event.CHANGE));
			}
		}
		
		/**
		 * 이벤트 핸들러, 텍스트필드 
		 * @param	event
		 */
		public function onTextInput(event:TextEvent):void
		{
			switch(event.type)
			{
			case TextEvent.TEXT_INPUT:
				if (!targetTextField) { targetTextField = event.target as TextField; }
				sbi = targetTextField.selectionBeginIndex;
				sei = targetTextField.selectionEndIndex;
				event.preventDefault();
				
				//한글 입력 상태이면서 콘트롤을 누르지 않았을 때.
				if (hmode && !_is_ctrl)
				{
					switch(getTypeFromAlphabet(event.text))
					{
					case CONSONANT:
					case VOWEL:
						var _tmp_alphabet:String = addAlphabet(event.text);
						targetTextField.replaceText(sbi, sei, _tmp_alphabet);
						targetTextField.setSelection(sbi + 1, sbi);
					break;
					
					case UNDEFINED:
					default:
						releaseSyllabic();
						targetTextField.replaceText(sbi,sei,event.text);
						targetTextField.setSelection(sbi + event.text.length, sbi + event.text.length);
						targetTextField.dispatchEvent(new Event(Event.CHANGE));
					break;
					}
					
				}
				//그 밖의 경우엔 평소대로 처리.
				else
				{
					event.target.replaceText(sbi,sei,event.text);
					event.target.setSelection(sbi + event.text.length, sbi + event.text.length);
					targetTextField.dispatchEvent(new Event(Event.CHANGE));
				}
			break;
			}
		}
		
		public function onChange(event:Event):void
		{
			switch(event.type)
			{
			case Event.CHANGE:
				if (_is_backspace && _array_code.length > 0)
				{
					var _tmp_alphabet:String = backspace();
					
					sbi = targetTextField.selectionBeginIndex;
					sei = sbi+_tmp_alphabet.length;
					targetTextField.replaceText(sbi, sbi, _tmp_alphabet);
					targetTextField.setSelection(sei, sbi);
				}
			break;
			}
		}
		
		public function onMouse(event:MouseEvent):void
		{
			switch(event.type)
			{
			case MouseEvent.CLICK:
				if (_array_code.length > 0)
				{
					var _tmp_sbi:int = targetTextField.selectionBeginIndex;
					releaseSyllabic();
					sei = sbi = _tmp_sbi;
					targetTextField.setSelection(sei, sbi);
				}
			break;
			}
		}
		
		/**
		 * 이벤트 핸들러, 키보드
		 * @param	event
		 */
		public function onKeyboard(event:KeyboardEvent):void
		{
			switch(event.type)
			{
			case KeyboardEvent.KEY_DOWN:
				switch(event.keyCode)
				{
				case 21:
					hmode = !hmode;
					IME.conversionMode = IMEConversionMode.ALPHANUMERIC_HALF;
					releaseSyllabic();
				break;
				
				case 229:
					if(IME.conversionMode != IMEConversionMode.ALPHANUMERIC_HALF)
					{
						hmode = !hmode;
						IME.conversionMode = IMEConversionMode.ALPHANUMERIC_HALF;
						releaseSyllabic();
					}
				break;
				
				case Keyboard.PAGE_DOWN:
				case Keyboard.PAGE_UP:
				case Keyboard.HOME:
				case Keyboard.END:
				case Keyboard.LEFT:
				case Keyboard.RIGHT:
				case Keyboard.UP:
				case Keyboard.DOWN:
					if (_array_code.length > 0) { releaseSyllabic(); }
				break;
				
				case Keyboard.BACKSPACE:
					_is_backspace = true;
				break;
				
				default:
					_is_ctrl = event.ctrlKey;
					_is_alt = event.altKey;
				break;
				}
			break;
			
			case KeyboardEvent.KEY_UP:
				switch(event.keyCode)
				{
				case Keyboard.BACKSPACE:
					_is_backspace = false;
				break;
				
				default:
					_is_ctrl = event.ctrlKey;
					_is_alt = event.altKey;
				break;
				}
			break;
			}
		}
	}
}